unit ServiceManager;

interface
uses classes, sysutils, windows, WinSvc;

Type TSVCStatus =
                     (st_STOPPED,
                      st_START_PENDING,
                      st_STOP_PENDING,
                      st_RUNNING,
                      st_CONTINUE_PENDING,
                      st_PAUSE_PENDING,
                      st_PAUSED);



Type
  TServiceManager = class(TComponent)
    private
      FSCMHandle:         SC_HANDLE;
      FServiceHandle:     SC_HANDLE;
      fWaitTime:          Longint;
      fErrorMessage:      String;
      fServiceName:       String;
      Function GetOSServiceManager: Boolean;
      Function GetServiceHandle(aServiceName: String): Boolean;
      Function GetServiceStatus(aServiceName: String): _SERVICE_STATUS;
      Function WaitForServiceStatus(aServiceName:String; ServiceStatus: DWORD): Boolean;
    public
      constructor Create(AOwner:TComponent); override;
      Destructor Destroy; override;
      Function AddService(aServiceName, aDisplayName, aFileName: string): Boolean;
      Function RemoveService(aServiceName:String): Boolean;
      Function ServiceExist(aServiceName:String): Boolean;
      Function ServiceStatus(aServiceName:String): TSVCStatus;  overload;
      Function ServiceStatusStr(aServiceName:String): String; overload;
      Function ServiceStop(aServiceName:String): Boolean;
      function ServiceStart(aServiceName:String):Boolean;
      property ErrorMessage:String read fErrorMessage;
    published
      property ServiceWaitTime: Longint read fWaitTime Write fWaitTime;

end;

implementation

{ TServiceManager }

function TServiceManager.AddService(aServiceName, aDisplayName,
  aFileName: string): Boolean;
var
  Args: pchar;
begin
  Result := False;
  if not GetOSServiceManager then exit;
  try
    FServiceHandle := CreateService(FSCMHandle,
                            PChar(aServiceName),
                            PChar(aDisplayName),
                            SERVICE_ALL_ACCESS,
                            SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS,
                            SERVICE_AUTO_START,
                            SERVICE_ERROR_IGNORE,
                            PChar(aFileName), nil, nil, nil, nil, nil);
    Args := nil;
    WinSvc.StartService(FServiceHandle, 0, Args);
    CloseServiceHandle(FServiceHandle);
    FServiceHandle := 0;
  finally
    CloseServiceHandle(FSCMHandle);
    FSCMHandle := 0;
  end;
  Result := True;
end;

constructor TServiceManager.Create(AOwner: TComponent);
begin
  inherited;
  FSCMHandle := 0;
  fWaitTime  := 2000;
end;

function TServiceManager.RemoveService(aServiceName: String): Boolean;
begin
  Result := False;
  if not GetServiceHandle(aServiceName) then exit;
  
  ServiceStop(aServiceName);
    
  if not DeleteService(FServiceHandle) then
  begin
    fErrorMessage := SysErrorMessage( GetLastError );
    exit;
  end;
  CloseServiceHandle( FServiceHandle);
  fServiceHandle := 0;
  Result := True;
end;

destructor TServiceManager.Destroy;
begin
  if FSCMHandle <> 0 then CloseServiceHandle(FSCMHandle);
  if FServiceHandle <> 0 then CloseServiceHandle(FServiceHandle);    
  inherited;
end;

function TServiceManager.GetOSServiceManager: Boolean;
begin
  if FSCMHandle = 0 then
  begin
    Result := False;
    FSCMHandle := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
    if FSCMHandle = 0 then
    begin
      fErrorMessage := SysErrorMessage( GetLastError );
      Exit;
    end
    else Result := True;
  end
  else Result := True;
end;

function TServiceManager.GetServiceHandle(aServiceName: String): Boolean;
begin
  Result := False;
  if not GetOSServiceManager then exit;
  if FServiceHandle <> 0 then CloseServiceHandle(fServiceHandle);
    

  FServiceHandle := OpenService(FSCMHandle, PChar(aServiceName), SERVICE_ALL_ACCESS);
  if FServiceHandle = 0 then
  begin
    fErrorMessage := SysErrorMessage( GetLastError );
    exit;
  end
  else
    Result := True;
end;

function TServiceManager.GetServiceStatus(aServiceName: String): _SERVICE_STATUS;
begin
  if not GetServiceHandle(aServiceName) then exit;
  if not QueryServiceStatus(FServiceHandle, Result) then
  begin
    fErrorMessage := SysErrorMessage( GetLastError );
    Raise Exception.Create(fErrorMessage);
  end;
end;


function TServiceManager.ServiceExist(aServiceName: String): Boolean;
begin
  Result := GetServiceHandle(aServiceName);
end;


function TServiceManager.ServiceStatus(aServiceName:String): TSVCStatus;
var
  Status: Word;
begin
  Status := GetServiceStatus(aServiceName).dwCurrentState;
  case Status of    //
   SERVICE_STOPPED:            result := st_STOPPED;
   SERVICE_START_PENDING:      result := st_START_PENDING;
   SERVICE_STOP_PENDING:       result := st_STOP_PENDING;
   SERVICE_RUNNING:            result := st_RUNNING;
   SERVICE_CONTINUE_PENDING:   result := st_CONTINUE_PENDING;
   SERVICE_PAUSE_PENDING:      result := st_PAUSE_PENDING;
   SERVICE_PAUSED:             result := st_PAUSED;
  end;    // case
end;

function TServiceManager.ServiceStatusStr(aServiceName: String): String;
var
  Status: Word;
begin
  Status := GetServiceStatus(aServiceName).dwCurrentState;
  case Status of    //
   SERVICE_STOPPED:            result := 'STOPPED';
   SERVICE_START_PENDING:      result := 'START_PENDING';
   SERVICE_STOP_PENDING:       result := 'STOP_PENDING';
   SERVICE_RUNNING:            result := 'RUNNING';
   SERVICE_CONTINUE_PENDING:   result := 'CONTINUE_PENDING';
   SERVICE_PAUSE_PENDING:      result := 'PAUSE_PENDING';
   SERVICE_PAUSED:             result := 'PAUSED';
  end;    // case
end;

function TServiceManager.ServiceStop(aServiceName: String): Boolean;
var
  Status: Word;
  ServiceStatus:       _SERVICE_STATUS;
begin
  Result := False;
  if not GetOSServiceManager then exit;
  try
    Status := GetServiceStatus(aServiceName).dwCurrentState;
  Except
    exit;
  end;

  if Status = SERVICE_STOPPED then
  begin
    Result := True;
    exit;
  end;

  if not ControlService(FServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus) then
  begin
    fErrorMessage := SysErrorMessage( GetLastError );
    exit;
  end;

  if WaitForServiceStatus(aServiceName, SERVICE_STOPPED) then Result := True
  else  Result := False;
end;

function TServiceManager.ServiceStart(aServiceName: String): Boolean;
Var
  schs: SC_Handle;
  ss: WinSVC.TServiceStatus;
  psTemp: PChar;
  dwChkP: DWord;
Begin
  ss.dwCurrentState := 0;
  if not GetOSServiceManager then Exit;

  If (FSCMHandle > 0) Then
  Begin
    schs := OpenService( FSCMHandle, PChar(aServiceName), SERVICE_START Or SERVICE_QUERY_STATUS);
    If (schs > 0) Then
    Begin
      psTemp := Nil;
      If (StartService( schs, 0, psTemp)) Then
      Begin
        If (QueryServiceStatus( schs, ss)) Then
        Begin
          While (SERVICE_RUNNING <> ss.dwCurrentState) Do
          Begin
            dwChkP := ss.dwCheckPoint;
            Sleep(ss.dwWaitHint);

            If (Not QueryServiceStatus( schs, ss)) Then break;
            If (ss.dwCheckPoint < dwChkP) Then break;
          End;
        End;
      End;
      CloseServiceHandle(schs);
    End;
    CloseServiceHandle(FSCMHandle);
  End;

  Result := SERVICE_RUNNING = ss.dwCurrentState;
end;


function TServiceManager.WaitForServiceStatus(aServiceName:String; 
  ServiceStatus: DWORD): Boolean;
var
  sp: LongWord;
begin
  Result := False;

  sp := GetTickCount;
  while ( GetTickCount - sp ) < fWaitTime do
  begin
    Try
      if GetServiceStatus(aServiceName).dwCurrentState = ServiceStatus then
      begin
        Result := True;
        Break;
      end
      else Sleep(100);
    Except
      break;
    end;
  end;    // while
end;

end.
